package main

import (
	"../common"
	"flag"
	"github.com/rcrowley/goagain"
	"net"
	"os"
	"strings"
	"time"

	logging "github.com/op/go-logging"
)

var format = logging.MustStringFormatter(
	`%{color}%{time:15:04:05.000} %{shortfunc} %{level:.4s} %{id:03x}%{color:reset} %{message}`)
var log = logging.MustGetLogger("golia-relay")

func init() {
	var logBackend = logging.NewLogBackend(os.Stderr, "", 0)
	logging.SetFormatter(format)
	logging.SetBackend(logBackend)
}

func load(conf *Config) error {
	logging.SetLevel(conf.LogLevel, "golia-relay")
	if conf.LogToFile {
		if logFile, err := os.OpenFile(DEFAULT_LOG, os.O_WRONLY|os.O_APPEND|os.O_APPEND, 0644); err != nil {
			log.Errorf("set log file error %s : %s \n", DEFAULT_LOG, err)
			return err
		} else {
			log.Info("set logBackend to file")
			logging.Reset()
			var logBackend = logging.NewLogBackend(logFile, "", 0)
			logging.SetFormatter(format)
			logging.SetBackend(logBackend)
		}
	}
	return nil
}

func main() {
	flag.Parse()
	configFile := DEFAULT_CONFIG
	if 1 == flag.NArg() {
		configFile = flag.Arg(0)
	} else {
		os.Exit(1)
	}
	log.Infof("using config :%s", configFile)
	conf, err := LoadFile(configFile)
	if err != nil {
		log.Errorf("Error parsing config %s: %s", configFile, err)
		os.Exit(1)
	}
	if load(conf) != nil {
		log.Errorf("Error parsing set log %v", err)
		os.Exit(1)
	}

	l, err := goagain.Listener()
	if nil != err {
		laddr, err := net.ResolveTCPAddr("tcp", conf.CarbonListenAddr)
		if nil != err {
			log.Error(err.Error())
			os.Exit(1)
		}
		l, err = net.ListenTCP("tcp", laddr)
		if nil != err {
			log.Error(err.Error())
			os.Exit(1)
		}
		if nil != err {
			log.Fatalf("create tcp listener error: %v", err)
			os.Exit(1)
		}
		log.Infof("listening on %s", l.Addr())
	} else {
		log.Infof("resuming listening on %s", l.Addr())
		if err := goagain.Kill(); nil != err {
			log.Fatalf("kill parent process err: %v", err)
			os.Exit(1)
		}
	}

	counter := NewCounter()

	cache := common.NewCacheManager(conf.CacheTimeUnit, conf.CacheSplitCount, conf.CacheCleanInterval)

	cache.AddFilter(func(dp common.DataPoint) bool {
		for _, name := range conf.CacheMetricNames {
			if strings.Contains(dp.Name, name) {
				return false
			}
		}
		return true
	})

	rcv := NewReceiver(l.(*net.TCPListener), nil, conf, counter, cache)

	go rcv.Run()
	defer rcv.Stop()
	go counter.Run()
	defer counter.Stop()

	if conf.DebugMode {
		go func() {
			for {
				if dp, ok := <-rcv.DataPointCh; ok {
					log.Infof("%v", dp)
					go cache.Add(dp)
				}
			}
		}()
	} else {
		sender := NewSender(conf, rcv.DataPointCh, counter, cache)
		go sender.Run()
	}

	go HttpListener(conf.WebListenAddr, counter, cache, conf)
	//defer cache.Close()

	// Block the main goroutine awaiting signals.
	if _, err := goagain.Wait(l); nil != err {
		log.Fatal(err)
	}

	if err := l.Close(); nil != err {
		log.Fatal(err)
		os.Exit(1)
		// Do whatever's necessary to ensure a graceful exit like waiting for
		// goroutines to terminate or a channel to become closed.
	}
	time.Sleep(1e9)
}
